/**
*   @file    Mcu_IPW.c
*   @version 1.0.1
*
*   @brief   AUTOSAR Mcu - Middle layer implementation.
*   @details Layer that implements the wrapper for routing data from/to external interface
*            to IP layer.
*
*   @addtogroup MCU
*   @{
*/
/*==================================================================================================
*   Project              : AUTOSAR 4.3 MCAL
*   Platform             : ARM
*   Peripheral           : MC
*   Dependencies         : none
*
*   Autosar Version      : 4.3.1
*   Autosar Revision     : ASR_REL_4_3_REV_0001
*   Autosar Conf.Variant :
*   SW Version           : 1.0.1
*   Build Version        : S32K14x_MCAL_1_0_1_RTM_ASR_REL_4_3_REV_0001_20190621
*
*   (c) Copyright 2006-2016 Freescale Semiconductor, Inc. 
*       Copyright 2017-2019 NXP
*   All Rights Reserved.
==================================================================================================*/
/*==================================================================================================
==================================================================================================*/


#ifdef __cplusplus
extern "C"
{
#endif


/*==================================================================================================
*                                        INCLUDE FILES
* 1) system and project includes
* 2) needed interfaces from external units
* 3) internal and external interfaces from this unit
==================================================================================================*/
/* Header file with prototype functions defines in this layer. */
#include "Mcu_IPW.h"
#include "Mcu_IPW_Irq.h"

/* Header files that are called from IPW layer. */
#include "Mcu_PCC.h"
#include "Mcu_PMC.h"
#include "Mcu_RCM.h"
#include "Mcu_SCG.h"
#include "Mcu_SIM.h"
#include "Mcu_SMC.h"
#include "Mcu_CMU.h"

#include "Reg_eSys_CMU.h"
#include "Reg_eSys_PCC.h"
#include "Reg_eSys_SCG.h"
#include "Mcu_CortexM4.h"

/* Mcu clock configuration structure used at a moment by the MCU driver.
   When the Mcu_InitClock() API is called this pointer will be different from NULL_PTR - used as a
    check trigger by Mcu_DistributePllClock() API.
*/
#if (MCU_INIT_CLOCK == STD_ON)
#define MCU_START_SEC_VAR_INIT_UNSPECIFIED
#include "Mcu_MemMap.h"

/** @violates @ref Mcu_IPW_c_REF_4 MISRA 2004 Required Rule 8.7, these object are used trough the entire MCU code*/
static P2CONST( Mcu_ClockConfigType, MCU_VAR, MCU_APPL_CONST) Mcu_pClockConfig = NULL_PTR;

#define MCU_STOP_SEC_VAR_INIT_UNSPECIFIED
#include "Mcu_MemMap.h"
#endif /* (MCU_INIT_CLOCK == STD_ON) */



/*==================================================================================================
                                   LOCAL FUNCTION PROTOTYPES
==================================================================================================*/
#define MCU_START_SEC_CODE
#include "Mcu_MemMap.h"

#if (MCU_ENTER_LOW_POWER_MODE == STD_ON)
static FUNC( void, MCU_CODE) Mcu_Ipw_DisableFircClock(VAR( void, AUTOMATIC));
static FUNC( void, MCU_CODE) Mcu_Ipw_DisableSoscClock(VAR( void, AUTOMATIC));
#endif


/*==================================================================================================
                                       LOCAL FUNCTIONS
==================================================================================================*/
#if (MCU_ENTER_LOW_POWER_MODE == STD_ON)
/**
* @brief            This function will disable Firc clock
*/

static FUNC( void, MCU_CODE) Mcu_Ipw_DisableFircClock(VAR( void, AUTOMATIC))
{
    VAR (uint32, AUTOMATIC) u32SystemResetIsrConfig;
    
    /* Configurable SIRC as system clock */
    Call_Mcu_SCG_DropSysClkToSircInRunMode();

    /* get the current System Reset Interrupt Enable settings */
    u32SystemResetIsrConfig = Mcu_RCM_GetCurrentSystemResetIsrSettings();

    /* Configure all reset sources to be 'Reset' */
    Call_Mcu_RCM_SystemResetIsrConfig();

    /* Disable Firc Clock */
    Call_Mcu_SCG_DisableFircClock();
    
    /* Restore System Reset Interrupt Config */
    Call_Mcu_RCM_RestoreSystemResetIsrConfig(u32SystemResetIsrConfig);
}

/**
* @brief            This function will disable SOSC clock
*/

static FUNC( void, MCU_CODE) Mcu_Ipw_DisableSoscClock(VAR( void, AUTOMATIC))
{
    VAR (uint32, AUTOMATIC) u32SystemResetIsrConfig;
    
    /* Configurable SIRC as system clock */
    Call_Mcu_SCG_DropSysClkToSircInRunMode();

    /* get the current System Reset Interrupt Enable settings */
    u32SystemResetIsrConfig = Mcu_RCM_GetCurrentSystemResetIsrSettings();

    /* Configure all reset sources to be 'Reset' */
    Call_Mcu_RCM_SystemResetIsrConfig();

    /* Disable SOSC Clock */
    Call_Mcu_SCG_DisableSoscClock();
    
    /* Restore System Reset Interrupt Config */
    Call_Mcu_RCM_RestoreSystemResetIsrConfig(u32SystemResetIsrConfig);
}
#endif


/*==================================================================================================
                                       GLOBAL FUNCTIONS
==================================================================================================*/
/**
* @brief            This function initializes the MCU module.
* @details          The function initializes the SIM, RCM, PMC, SMC modules.
*                   Called by:
*                       - Mcu_Init() from HLD.
*
* @param[in]        Mcu_pHwIPsConfigPtr   Pointer to IPW configuration structure.
*
* @return           void
*
*/
FUNC( void, MCU_CODE) Mcu_Ipw_Init(P2CONST( Mcu_HwIPsConfigType, AUTOMATIC, MCU_APPL_CONST) Mcu_pHwIPsConfigPtr)
{
#if (MCU_DISABLE_SIM_INIT == STD_OFF)
    /* Init SIM settings. */
    Call_Mcu_SIM_Init( Mcu_pHwIPsConfigPtr->SIM_pConfig );
#endif

#if (MCU_DISABLE_RCM_INIT == STD_OFF)
    /* Init the RCM module */
    Call_Mcu_RCM_ResetInit(Mcu_pHwIPsConfigPtr->RCM_pResetConfig);
#endif

#if (MCU_DISABLE_PMC_INIT == STD_OFF)
    /* Configure the Power Management Unit. */
    Call_Mcu_PMC_PowerInit( Mcu_pHwIPsConfigPtr->PMC_pConfig);
#endif

#if (MCU_DISABLE_SMC_INIT == STD_OFF)    
    Call_Mcu_SMC_AllowedModesConfig(Mcu_pHwIPsConfigPtr->SMC_pConfig);
#endif
}


#if (MCU_INIT_CLOCK == STD_ON)
/**
* @brief            This function initializes the clock structure.
* @details          This function intializes the clock structure by configuring the SIM, SCG, PCC modules.
*                   Called by:
*                       - Mcu_InitClock() from HLD.
*
* @param[in]        Mcu_pClockConfigPtr   Pointer to clock configuration structure
*                   (member of 'Mcu_ConfigType' struct).
*
* @return           void
*
*/
FUNC( void, MCU_CODE) Mcu_Ipw_InitClock(P2CONST( Mcu_ClockConfigType, AUTOMATIC, MCU_APPL_CONST) Mcu_pClockConfigPtr)
{
    /* Save configs to global variable for other usage */
    Mcu_pClockConfig = Mcu_pClockConfigPtr;
    
#if (IPV_CMU == IPV_CMU_00_00_00_01)
#ifdef MCU_ENABLE_CMU_PERIPHERAL
#if(MCU_ENABLE_CMU_PERIPHERAL == STD_ON)
    /* Disable CMU0. */
    if(Mcu_PCC_GetStatus(PCC_CMU0_ADDR32) & PCC_CMU0_RWBITS_MASK32)
    {
        Mcu_CMU_Disable_CMU(CMU0_CHANNEL);
    }
    
    /* Disable CMU1. */
    if(Mcu_PCC_GetStatus(PCC_CMU1_ADDR32) & PCC_CMU1_RWBITS_MASK32)
    {
        Mcu_CMU_Disable_CMU(CMU1_CHANNEL);
    }
#endif
#endif
#endif

    Call_Mcu_SIM_ClockConfig(Mcu_pClockConfig->SIM_pClockConfig);

    /* Configure SIRC and then select it as system clock by default. This is needed to apply new configuration for Pll
       in case of the Pll selected as system clock previously. This is possible only when sys clock is under Mcu control.
    */
    if(SCG_SYS_CLK_NOT_UNDER_MCU_CONTROL != Mcu_pClockConfigPtr->SCG_pClockConfig->u32RunClockControlConfiguration)
    {
        Call_Mcu_SCG_DropSystemClockToSirc();
    }
    
    /*After that, configure all parameters here */
    /* Configure FIRC */
    if (MCU_IPW_SIRC_UNDER_MCU_CONTROL == (Mcu_pClockConfig->u8ClockSourcesControl & MCU_IPW_SIRC_UNDER_MCU_CONTROL))
    {
        Call_Mcu_SCG_SircInit(Mcu_pClockConfig->SCG_pClockConfig);        
    }   
    
    /* Re-Configure FIRC by user configuration */
    if (MCU_IPW_FIRC_UNDER_MCU_CONTROL == (Mcu_pClockConfig->u8ClockSourcesControl & MCU_IPW_FIRC_UNDER_MCU_CONTROL))
    {
        Call_Mcu_SCG_FircInit(Mcu_pClockConfig->SCG_pClockConfig);
    }
    /* Configure SOSC */
    if (MCU_IPW_SOSC_UNDER_MCU_CONTROL == (Mcu_pClockConfig->u8ClockSourcesControl & MCU_IPW_SOSC_UNDER_MCU_CONTROL))
    {
        Call_Mcu_SCG_SoscInit(Mcu_pClockConfig->SCG_pClockConfig);
    }    
    
#if (MCU_NO_PLL == STD_OFF)
    /* Configure SPLL */
    if (MCU_IPW_SPLL_UNDER_MCU_CONTROL == (Mcu_pClockConfig->u8ClockSourcesControl & MCU_IPW_SPLL_UNDER_MCU_CONTROL))
    {
        Call_Mcu_SCG_SpllInit(Mcu_pClockConfig->SCG_pClockConfig);
    }
#endif  /* MCU_NO_PLL */
    
    /* Configure System Clock */
    if(SCG_SYS_CLK_NOT_UNDER_MCU_CONTROL != Mcu_pClockConfigPtr->SCG_pClockConfig->u32RunClockControlConfiguration)
    {
        Call_Mcu_SCG_SystemClockInit(Mcu_pClockConfigPtr->SCG_pClockConfig);
    }
    
    /* set up the clock distribution tree */
    Call_Mcu_PCC_PeripheralConfig( Mcu_pClockConfigPtr->PCC_pConfig ) ;
    
#if (IPV_CMU == IPV_CMU_00_00_00_01)
#ifdef MCU_ENABLE_CMU_PERIPHERAL
#if(MCU_ENABLE_CMU_PERIPHERAL == STD_ON)
    
    if (
         (MCU_IPW_FIRC_UNDER_MCU_CONTROL == (Mcu_pClockConfig->u8ClockSourcesControl & MCU_IPW_FIRC_UNDER_MCU_CONTROL)) &&
         (((*(Mcu_pClockConfig->SCG_pClockConfig)->apFircClockConfig)[SCG_FIRCCSR_CONFIG_REG].u32RegisterData & SCG_FIRCCSR_FIRCEN_MASK32) == SCG_FIRCCSR_FIRCEN_MASK32)
        )
    {
        /* Configure CMU */
        Mcu_CMU_Init( Mcu_pClockConfigPtr->CMU_pConfig);
    }

#endif
#endif
#endif
}
#endif /* (MCU_INIT_CLOCK == STD_ON) */


#if (MCU_INIT_CLOCK == STD_ON)
#if (MCU_NO_PLL == STD_OFF)
/**
* @brief              This function activates the main PLL as the system clock source.
* @details            This function sets the PLL as the system clock and also enables monitoring.
*                     Called by:
*                       - Mcu_DistributePllClock() from HLD.
*
* @return           void
*
*/
FUNC( void, MCU_CODE) Mcu_Ipw_DistributePllClock( VAR( void, AUTOMATIC) )
{

    if ( NULL_PTR != Mcu_pClockConfig)
    {
        /* if system clock tree is under MCU control */
        if(SCG_SYS_CLK_NOT_UNDER_MCU_CONTROL != Mcu_pClockConfig->SCG_pClockConfig->u32RunClockControlConfiguration)
        {
            /* Select Pll as system clock */
            Call_Mcu_SCG_SystemClockInit(Mcu_pClockConfig->SCG_pClockConfig);
        }
    }
}
#endif /* (MCU_NO_PLL == STD_OFF) */
#endif /* (MCU_INIT_CLOCK == STD_ON) */

#if (MCU_NO_PLL == STD_OFF)
/**
* @brief            This function returns the lock status of the PLL.
* @details          The user takes care that the PLL is locked by executing Mcu_GetPllStatus.
*                   If the MCU_NO_PLL is TRUE the MCU_GetPllStatus has to return
*                   MCU_PLL_STATUS_UNDEFINED.
*                   Called by:
*                       - Mcu_GetPllStatus() from HLD.
*
* @return           Provides the lock status of the PLL.
* @retval           MCU_PLL_STATUS_UNDEFINED   PLL Status is unknown.
* @retval           MCU_PLL_LOCKED   PLL is locked.
* @retval           MCU_PLL_UNLOCKED    PLL is unlocked.
*
*/
FUNC( Mcu_PllStatusType, MCU_CODE) Mcu_Ipw_GetPllStatus( VAR( void, AUTOMATIC))
{
    /* Pll status variable. */
    VAR( Mcu_PllStatusType, AUTOMATIC)   ePllStatus = MCU_PLL_STATUS_UNDEFINED;
    VAR( Mcu_SCG_PllStatusType, AUTOMATIC) eSpllStatus ;

    /* get the status from each peripheral */
    eSpllStatus = Mcu_SCG_GetPLLStatus();

    /* if a pll is unlocked return MCU_PLL_UNLOCKED */
    if ( MCU_SPLL_LOCKED == eSpllStatus )
    {
        ePllStatus = MCU_PLL_LOCKED ;
    }
    else
    {
        ePllStatus = MCU_PLL_UNLOCKED ;
    }

    /* Return the PLL status. */
    return (Mcu_PllStatusType)ePllStatus;
}
#endif /* (MCU_NO_PLL == STD_OFF) */

/**
* @brief            This function initializes the mode structure.
* @details          This function intializes the mode structure by configuring the SMC module.
*                   Called by:
*                       - Mcu_SetMode() from HLD.
*
* @param[in]        Mcu_pModeConfigPtr   Pointer to mode configuration structure.
*
* @return           void
*
*/
FUNC( void, MCU_CODE) Mcu_Ipw_SetMode(P2CONST( Mcu_ModeConfigType, AUTOMATIC, MCU_APPL_CONST) Mcu_pModeConfigPtr)
{
#if (MCU_ENTER_LOW_POWER_MODE == STD_ON)
    if ((MCU_VLPS_MODE == Mcu_pModeConfigPtr->u32PowerMode) || (MCU_VLPR_MODE == Mcu_pModeConfigPtr->u32PowerMode))
    {
        /*
        * All clock monitors are always disabled when chip in a low power mode.
        * However, to prevent unexpected loss of clock reset events, we should
        * disable them before entering any low power modes, including VLPR and VLPS. */        
        /** @violates @ref Mcu_IPW_c_REF_5 The comma operator shall not be used. */
        /**  @violates @ref Mcu_IPW_c_REF_7 MISRA 2004 Rule 16.9, function identifier */
        Call_Mcu_SCG_DisableClockMonitors();

#if (IPV_CMU == IPV_CMU_00_00_00_01)
#ifdef MCU_ENABLE_CMU_PERIPHERAL
#if(MCU_ENABLE_CMU_PERIPHERAL == STD_ON)
        /* Disable CMU before Disable FIRC. */
       /*  Mcu_CMU_DeInit(); */
        if(Mcu_PCC_GetStatus(PCC_CMU0_ADDR32) & PCC_CMU0_RWBITS_MASK32)
        {
            Mcu_CMU_Disable_CMU(CMU0_CHANNEL);
        }
        
        if(Mcu_PCC_GetStatus(PCC_CMU1_ADDR32) & PCC_CMU1_RWBITS_MASK32)
        {
            Mcu_CMU_Disable_CMU(CMU1_CHANNEL);
        }
#endif
#endif
#endif

        /* Disable FIRC in RUN mode before initiating a mode transition request to any low power mode. */
        Mcu_Ipw_DisableFircClock();

        /* Disable SOSC in RUN mode before initiating a mode transition request to any low power mode. */
        Mcu_Ipw_DisableSoscClock();

        if (MCU_VLPS_MODE == Mcu_pModeConfigPtr->u32PowerMode)
        {
            /*This enable chip go into deep sleep mode by setting bit SLEEPDEEP */
            Call_Mcu_CM4_EnableDeepSleep();
        
#if (MCU_NO_PLL == STD_OFF)
            /* When entering VLPS mode, the PLL must be disabled before making any mode transition. */
            Call_Mcu_SCG_DisableSpllClock();
#endif /* (MCU_NO_PLL == STD_OFF) */
        }
    }

    if ((MCU_STOP1_MODE == Mcu_pModeConfigPtr->u32PowerMode) || (MCU_STOP2_MODE == Mcu_pModeConfigPtr->u32PowerMode))
    {
        /*This enable chip go into deep sleep mode by setting bit SLEEPDEEP */
        Call_Mcu_CM4_EnableDeepSleep();
    }
#endif

    /* Request new mode transition to MC_ME. */
    Call_Mcu_SMC_ModeConfig( Mcu_pModeConfigPtr);
    
#if (MCU_ENTER_LOW_POWER_MODE == STD_ON)
    if ((MCU_VLPS_MODE == Mcu_pModeConfigPtr->u32PowerMode) || 
        (MCU_STOP1_MODE == Mcu_pModeConfigPtr->u32PowerMode) || (MCU_STOP2_MODE == Mcu_pModeConfigPtr->u32PowerMode)
       )
    {
        /*This will clear SLEEPDEEP bit after wake-up */
        Call_Mcu_CM4_DisableDeepSleep();
    }
#endif
}


#ifdef MCU_DISABLE_CMU_API
#if (MCU_DISABLE_CMU_API == STD_ON)
FUNC( void, MCU_CODE ) Mcu_Ipw_DisableCmu(VAR (uint8, AUTOMATIC) u8IndexCmu)
{
    Mcu_CMU_Disable_CMU(u8IndexCmu);
}
#endif
#endif

#ifdef MCU_SRAM_RETEN_CONFIG_API
#if (MCU_SRAM_RETEN_CONFIG_API == STD_ON)
FUNC( void, MCU_CODE ) Mcu_Ipw_SRAMRetentionConfig(VAR (Mcu_SRAMRetenConfigType, AUTOMATIC) eSRAMRetenConfig)
{
    Mcu_SIM_SRAMRetentionConfig(eSRAMRetenConfig);
}
#endif
#endif

#if (MCU_PERFORM_RESET_API == STD_ON)
/**
* @brief            This function performs a microcontroller reset.
* @details          This function performs a microcontroller reset by using the hardware feature of
*                   the microcontroller.
*                   Called by:
*                       - Mcu_PerformReset() from HLD.
*
* @param[in]        Mcu_pHwIPsConfigPtr  Pointer to LLD configuration structure (member of
*                   'Mcu_ConfigType' struct).
*
* @return           void
*
*/
FUNC( void, MCU_CODE) Mcu_Ipw_PerformReset(P2CONST( Mcu_HwIPsConfigType, AUTOMATIC, MCU_APPL_CONST) Mcu_pHwIPsConfigPtr)
{
    /* Performs a micro controller reset. */
    MCU_PARAM_UNUSED(Mcu_pHwIPsConfigPtr);
    Call_Mcu_CM4_SystemReset();
}
#endif /* (MCU_PERFORM_RESET_API == STD_ON) */



/**
* @brief            This function returns the reset reason.
* @details          This routine returns the Reset reason that is read from the hardware.
*                   Called by:
*                       - Mcu_GetResetReason() from HLD.
*
* @param[in]        None
*
* @return           void
*
*/
FUNC( Mcu_ResetType, MCU_CODE) Mcu_Ipw_GetResetReason( VAR( void, AUTOMATIC))
{
    VAR( Mcu_ResetType, AUTOMATIC)   eResetReason = MCU_RESET_UNDEFINED;

    eResetReason = (Mcu_ResetType)Call_Mcu_RCM_GetResetReason();
    return (Mcu_ResetType) eResetReason;
}


/**
* @brief            This function returns the reset reason.
* @details          This routine returns the Reset reason that is read from the hardware.
*                   Called by:
*                       - Mcu_GetResetReason() from HLD.
*
* @param[in]        None
*
* @return           void
*
*/
FUNC( Mcu_RawResetType, MCU_CODE) Mcu_Ipw_GetResetRawValue( VAR( void, AUTOMATIC))
{
    VAR( Mcu_RawResetType, AUTOMATIC) ResetReason;

    ResetReason = (Mcu_RawResetType)Call_Mcu_RCM_GetResetRawValue();
    return (Mcu_RawResetType) ResetReason;
}

#define MCU_STOP_SEC_CODE
#include "Mcu_MemMap.h"


#ifdef __cplusplus
}
#endif

/** @} */

